home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / QuickDraw GX / QuickDraw GX Info / QuickDraw GX Interfaces / Interfaces & Libraries / graphics libraries / conic library.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-30  |  4.0 KB  |  142 lines  |  [TEXT/MPS ]

  1. /* graphics libraries:  
  2.     conic library
  3.     by Mike Reed
  4.     Copyright 1987 - 1991 Apple Computer, Inc.  All rights reserved.    */
  5.  
  6. #include "graphics libraries.h"
  7.  
  8. /*
  9.  *  kNumPoints must be at least 2^n + 2 where n is kMaxRecursion.
  10.  *  Current static implementation limits ctr bits to 1 long so
  11.  *  kMaxRecursion cannot be greater than 4
  12.  */
  13. #define kMaxRecursion       4
  14.  
  15. #define kNumPoints          ((1L << kMaxRecursion) + 2)
  16.  
  17. #define kNumOfStaticLongs   (2 + kNumPoints*2)
  18.  
  19. /*
  20.  *  This dude just does what it says.  I broke up some of the formulas
  21.  *  to try and reduce overflow of intermediate results.  This is a good
  22.  *  place to optimize with assembler for speed and accuracy.
  23.  */
  24. static void SubdivideConic(register const conic *c, conic *left, conic *rite)
  25. {
  26.     register Fixed lambda = c->lambda;
  27.     register Fixed lambdaPlusOne = lambda + fixed1;
  28.     register Fixed lambdaBx = FixedMultiply(lambda, c->b.x);
  29.     register Fixed lambdaBy = FixedMultiply(lambda, c->b.y);
  30.  
  31.     left->a = c->a;
  32.     left->b.x = FixedDivide(c->a.x + lambdaBx, lambdaPlusOne);
  33.     left->b.y = FixedDivide(c->a.y + lambdaBy, lambdaPlusOne);
  34.  
  35.     left->c.x = FixedDivide((c->a.x + c->c.x >> 1) + lambdaBx, lambdaPlusOne);
  36.     left->c.y = FixedDivide((c->a.y + c->c.y >> 1) + lambdaBy, lambdaPlusOne);
  37.     rite->a = left->c;
  38.  
  39.     rite->b.x = FixedDivide(c->c.x + lambdaBx, lambdaPlusOne);
  40.     rite->b.y = FixedDivide(c->c.y + lambdaBy, lambdaPlusOne);
  41.     rite->c = c->c;
  42.  
  43.     left->lambda = rite->lambda = FixedSquareRoot(lambdaPlusOne >> 1);
  44. }
  45. /*
  46.  *  This guy fills out ptPtr with ON/OFF-gxCurve points.  recursion is the maximum
  47.  *  depth I can call myself, since storage for ptPtr is pre-allocated.
  48.  */
  49. static gxPoint* Conic2Path(const conic *aConic, gxPoint *ptPtr, short recursion)
  50. {
  51.     if ((recursion-- > 0))
  52.     {
  53.         conic leftConic, riteConic;
  54.         SubdivideConic(aConic, &leftConic, &riteConic);
  55.         ptPtr = Conic2Path(&leftConic, ptPtr, recursion);
  56.         ptPtr = Conic2Path(&riteConic, ptPtr, recursion);
  57.     }
  58.     else
  59.     {
  60.         *ptPtr++ = aConic->b;
  61.     }
  62.     return ptPtr;
  63. }
  64.  
  65. /*
  66.  *  The lambda for a parabola is 1.  Error should be
  67.  *      (a - 2b + c) (lambda - 1)
  68.  *      -----------------------
  69.  *               8
  70.  */
  71. static short RecursionDepth(register const conic *aConic, register Fixed tolerance)
  72. {
  73.     register Fixed dx, dy;
  74.  
  75.     {
  76.         register Fixed tmp = aConic->lambda - fixed1 + 4 >> 3;
  77.         dx = aConic->b.x;
  78.         dx = FixedMultiply( aConic->a.x - dx - dx + aConic->c.x, tmp );
  79.         dy = aConic->b.y;
  80.         dy = FixedMultiply( aConic->a.y - dy - dy + aConic->c.y, tmp );
  81.     }
  82.     {
  83.         register short count;
  84.         register Fixed length = Magnitude( dx, dy );
  85.         for (count = 0; length > tolerance; count++)
  86.             length >>= 4;
  87.         return count;
  88.     }
  89. }
  90.  
  91. /*
  92.  *  Given a conic geometry, returns a gxPath
  93.  */
  94. static void ConicPath(long *storage, const conic *aConic)
  95. {
  96.     Fixed       tolerance = GXGetShapeCurveError( GXGetDefaultShape(gxPathType) );
  97.     gxPoint*  ptPtr;
  98.     long*   longp = storage;
  99.     short   count;
  100.  
  101.     count = RecursionDepth(aConic, tolerance);
  102.     if (count > kMaxRecursion)
  103.         count = kMaxRecursion;
  104.  
  105.     ptPtr = (gxPoint*)&storage[2];
  106.     *ptPtr++ = aConic->a;
  107.     ptPtr = Conic2Path(aConic, ptPtr, count);
  108.     *ptPtr++ = aConic->c;
  109.  
  110.     count = ptPtr - (gxPoint*)&storage[2];
  111.     storage[0] = count;
  112.     storage[1] = 0x7FFFFFFF ^ ( 1L << 32 - count );
  113. }
  114.  
  115. /***********************************************************************/
  116.  
  117. void DrawConic(const conic *aConic, gxShapeFill aFill)
  118. {
  119.     gxShape s = NewConic(aConic);
  120.     if (aFill)
  121.         GXSetShapeFill(s, aFill);
  122.     GXSetShapeAttributes(s, GXGetShapeAttributes(s) & ~gxCachedShape);
  123.     GXDrawShape(s);
  124.     GXDisposeShape(s);
  125. }
  126.  
  127. gxShape NewConic(const conic *aConic)
  128. {
  129.     long    storage[kNumOfStaticLongs];
  130.     
  131.     ConicPath(storage, aConic);
  132.     return NewPath((gxPath*)storage);
  133. }
  134.  
  135. void SetConic(gxShape dest, const conic *aConic)
  136. {
  137.     long    storage[kNumOfStaticLongs];
  138.     
  139.     ConicPath(storage, aConic);
  140.     SetPath(dest, 0, (gxPath*)storage);
  141. }
  142.